package com.adf.gencode;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.setting.Setting;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.IDbQuery;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.*;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.util.*;
import java.nio.file.Paths;

public class AdfFreemarkerTemplateEngine extends FreemarkerTemplateEngine {

    //生成的配置的文件名
    private String genConfigFileName = "genConfig.xml";

    @Override
    protected void outputService(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        String entityName = tableInfo.getEntityName();
        String tableName = tableInfo.getName();

        String entityExtName = entityName;
        Optional<AdfTable> optionalAdfTable = GlobalConfig.globalTableList.findFirst(t->{return t.getTableName().equals(tableName);});
        if(optionalAdfTable.isPresent()){
            String tmpName = optionalAdfTable.get().getEntityName();
            System.out.println("tmpName"+tmpName);

            if(!ObjectUtil.isNull(tmpName)){
                entityExtName = tmpName;
            }
        }
        else {
            System.out.println("当前表:" + tableName + ",在genConfig.xml不存在配置，还使用默认的命名");
        }

        objectMap.put("entityExtName",entityExtName);

        Service service = this.getConfigBuilder().getStrategyConfig().service();
        if (service.isGenerateService()) {
            String servicePath = this.getPathInfo(OutputFile.service);
            String serviceFile = String.format(servicePath + File.separator + "I"+entityExtName +"Service" + this.suffixJavaOrKt(), entityExtName);
            this.outputFile(this.getOutputFile(serviceFile, OutputFile.service), objectMap, this.templateFilePath(service.getServiceTemplate()), this.getConfigBuilder().getStrategyConfig().service().isFileOverride());
        }

        String serviceImplPath = this.getPathInfo(OutputFile.serviceImpl);
        if (service.isGenerateServiceImpl()) {
            String implFile = String.format(serviceImplPath + File.separator + entityExtName+"ServiceImpl" + this.suffixJavaOrKt(), entityExtName);
            this.outputFile(this.getOutputFile(implFile, OutputFile.serviceImpl), objectMap, this.templateFilePath(service.getServiceImplTemplate()), this.getConfigBuilder().getStrategyConfig().service().isFileOverride());
        }
    }

    /**
     * 自定义的方式来生成实体
     * @param tableInfo
     * @param objectMap
     */
    @Override
    protected void outputEntity(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {

        // 这里可以加入想要的内容 加入到objectMap中，然后在模板中进行使用

        System.out.println("自定义生成");

        String entityName = tableInfo.getEntityName();
        String tableName = tableInfo.getName();

        String entityExtName = entityName;
        Optional<AdfTable> optionalAdfTable = GlobalConfig.globalTableList.findFirst(t->{return t.getTableName().equals(tableName);});
        if(optionalAdfTable.isPresent()){
            String tmpName = optionalAdfTable.get().getEntityName();
            System.out.println("tmpName"+tmpName);

            if(!ObjectUtil.isNull(tmpName)){
                entityExtName = tmpName;
            }
        }
        else {
            System.out.println("当前表:" + tableName + ",在genConfig.xml不存在配置，还使用默认的命名");
        }

        objectMap.put("entityExtName",entityExtName);

        String entityPath = this.getPathInfo(OutputFile.entity);
        Entity entity = this.getConfigBuilder().getStrategyConfig().entity();
        com.baomidou.mybatisplus.generator.config.GlobalConfig globalConfig = this.getConfigBuilder().getGlobalConfig();
        if (entity.isGenerate()) {
            String entityFile = String.format(entityPath + File.separator + "%s" + this.suffixJavaOrKt(), entityExtName);
            this.outputFile(this.getOutputFile(entityFile, OutputFile.entity), objectMap, this.templateFilePath(globalConfig.isKotlin() ? entity.getKotlinTemplate() : entity.getJavaTemplate()), this.getConfigBuilder().getStrategyConfig().entity().isFileOverride());
        }


        //super.outputEntity(tableInfo, objectMap);
    }

    @Override
    protected void outputMapper(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {

        String entityName = tableInfo.getEntityName();
        String tableName = tableInfo.getName();


        Optional<AdfTable> optionalAdfTable = GlobalConfig.globalTableList.findFirst(t->{return t.getTableName().equals(tableName);});

        String entityExtName = entityName;

        if(optionalAdfTable.isPresent()){
            String tmpName = optionalAdfTable.get().getEntityName();
            System.out.println("tmpName"+tmpName);

            if(!ObjectUtil.isNull(tmpName)){
                entityExtName = tmpName;
            }
        }
        else {
            System.out.println("当前表:" + tableName + ",在genConfig.xml不存在配置，还使用默认的命名");
        }

        String newMapperName = entityExtName+"Mapper";
        objectMap.put("entityExtName",entityExtName);


        String mapperPath = this.getPathInfo(OutputFile.mapper);
        Mapper mapper = this.getConfigBuilder().getStrategyConfig().mapper();
        if (mapper.isGenerateMapper()) {
            String mapperFile = String.format(mapperPath + File.separator + newMapperName + this.suffixJavaOrKt(), entityExtName);
            this.outputFile(this.getOutputFile(mapperFile, OutputFile.mapper), objectMap, this.templateFilePath(mapper.getMapperTemplatePath()), this.getConfigBuilder().getStrategyConfig().mapper().isFileOverride());
        }

        String xmlPath = this.getPathInfo(OutputFile.xml);
        if (mapper.isGenerateMapperXml()) {
            String xmlFile = String.format(xmlPath + File.separator + newMapperName + ".xml", entityExtName);
            this.outputFile(this.getOutputFile(xmlFile, OutputFile.xml), objectMap, this.templateFilePath(mapper.getMapperXmlTemplatePath()), this.getConfigBuilder().getStrategyConfig().mapper().isFileOverride());
        }
    }

    @Override
    protected void outputController(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {

        Controller controller = this.getConfigBuilder().getStrategyConfig().controller();
        String controllerPath = this.getPathInfo(OutputFile.controller);
        if (controller.isGenerate()) {
            String entityName = tableInfo.getEntityName();
            String tableName = tableInfo.getName();
            Optional<AdfTable> optionalAdfTable = GlobalConfig.globalTableList.findFirst(t->{return t.getTableName().equals(tableName);});

            String entityExtName = entityName;

            if(optionalAdfTable.isPresent()){
                String tmpName = optionalAdfTable.get().getEntityName();
                System.out.println("tmpName"+tmpName);

                if(!ObjectUtil.isNull(tmpName)){
                    entityExtName = tmpName;
                }
            }
            else {
                System.out.println("当前表:" + tableName + ",在genConfig.xml不存在配置，还使用默认的命名");
            }

            objectMap.put("entityExtName",entityExtName);

            String controllerFile = String.format(controllerPath + File.separator + entityExtName+"Controller" + this.suffixJavaOrKt(), entityExtName);
            this.outputFile(this.getOutputFile(controllerFile, OutputFile.controller), objectMap, this.templateFilePath(controller.getTemplatePath()), this.getConfigBuilder().getStrategyConfig().controller().isFileOverride());
        }

        //super.outputController(tableInfo, objectMap);
    }

    @Override
    protected void outputCustomFile(@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {

        Map<String, String> customFilePath = (Map<String, String>)objectMap.get("setting");

        String voQueryXmlPath = (String)objectMap.get("voQueryXmlPath");

        System.out.println("voQueryXmlPath" + voQueryXmlPath);

        Setting setting = (Setting) objectMap.get("setting");
        String projectRootDir = setting.getStr("targetProject",System.getProperty("user.dir"));
        String resourcesPath = projectRootDir + "/"+TemplateUtil.createEngine().getTemplate(setting.get("resourcesPath")).render(setting);
        //vue 所在根目录
        String vueRootOutPath = setting.get("vueRootOutPath");

        String vueListOutPath = vueRootOutPath + "\\" +setting.get("vueListOutPath");
        String vueAddOutPath = vueRootOutPath + "\\" +setting.get("vueAddOutPath");
        String vueViewOutPath = vueRootOutPath + "\\" +setting.get("vueViewOutPath");
        String vueApiOutPath = vueRootOutPath + "\\" +setting.get("vueApiOutPath");

        //


        String entityName = tableInfo.getEntityName();
        customFiles.forEach(x->{

            String templatePath = x.getTemplatePath();


            if(templatePath.contains("vue.List")){
                // 说明是list 模板
                String filePath =vueListOutPath +"\\" + entityName.toLowerCase() + "\\list.vue";
                outputFile(new File(filePath),objectMap,x.getTemplatePath(),x.isFileOverride());

            } else if(templatePath.contains("vue.Add")){
                // 是编辑模板
                String filePath =vueAddOutPath + "\\" + entityName.toLowerCase() + "\\add.vue";
                outputFile(new File(filePath),objectMap,x.getTemplatePath(),x.isFileOverride());
            }else if(templatePath.contains("vue.View")){
                // 是编辑模板
                String filePath =vueViewOutPath + "\\" + entityName.toLowerCase() + "\\view.vue";
                outputFile(new File(filePath),objectMap,x.getTemplatePath(),x.isFileOverride());
            }else if(templatePath.contains("vue.Api")){
                // 是编辑模板
                String filePath =vueApiOutPath + "\\" + tableInfo.getName().replaceAll("^.*?_","") + ".ts";
                outputFile(new File(filePath),objectMap,x.getTemplatePath(),x.isFileOverride());
            }
            else if(templatePath.contains("vo.query.java")){
                // 是编辑模板
                String moduleName = setting.getStr("moduleName");
                String defaultPackageName = setting.getStr("basePackage") +"." + moduleName +".mapper";
                try {

                    List<AdfTable> lstTable = GlobalConfig.globalQueryList.findAll(table->{return true;});

                    for(AdfTable adfTable : lstTable){
                        String voClassName = adfTable.getEntityName();
                        if(ObjectUtil.isNull(voClassName)){
                            voClassName = adfTable.getTableName();
                        }
                        objectMap.put("voQuery_VoClassName",voClassName);
                        //得到Sql
                        String sql = adfTable.getSql();
                        generateVO("1",voClassName, sql,defaultPackageName,customFiles,objectMap,x);
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            else if(templatePath.contains("vo.querymapper.xml")){

                String voQueryXmlPath1 = resourcesPath + "/" + genConfigFileName;
                String moduleName = setting.getStr("moduleName");
                String defaultPackageName = setting.getStr("basePackage") +"." + moduleName +".mapper";
                try {

                    List<AdfTable> lstTable = GlobalConfig.globalQueryList.findAll(table->{return true;});

                    for(AdfTable adfTable : lstTable){
                        String voClassName = adfTable.getEntityName();
                        if(ObjectUtil.isNull(voClassName)){
                            voClassName = adfTable.getTableName();
                        }
                        objectMap.put("voQuery_VoClassName",voClassName);
                        //得到Sql
                        String sql = adfTable.getSql();
                        generateVO("2",voClassName, sql,defaultPackageName,customFiles,objectMap,x);
                    }


                } catch (Exception e) {
                    throw new RuntimeException(e);
                }


            }else if(templatePath.contains("vo.querymapper.java")){
                System.out.println("生成 vo.querymapper.java");

                String voQueryXmlPath1 = resourcesPath + "/voQuery.xml";
                String moduleName = setting.getStr("moduleName");
                String defaultPackageName = setting.getStr("basePackage") +"." + moduleName +".mapper";

                try {


                    List<AdfTable> lstTable = GlobalConfig.globalQueryList.findAll(table->{return true;});

                    for(AdfTable adfTable : lstTable){
                        String voClassName = adfTable.getEntityName();
                        if(ObjectUtil.isNull(voClassName)){
                            voClassName = adfTable.getTableName();
                        }
                        objectMap.put("voQuery_VoClassName",voClassName);
                        //得到Sql
                        String sql = adfTable.getSql();
                        generateVO("3",voClassName, sql,defaultPackageName,customFiles,objectMap,x);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }


            }else if(templatePath.contains("vo.query.service.interface")){
                System.out.println("生成 vo.query.service.interface");

                try {

                    List<AdfTable> lstTable = GlobalConfig.globalQueryList.findAll(table->{return true;                    });

                    for(AdfTable adfTable : lstTable)
                    {
                        String voClassName = adfTable.getEntityName();
                        if(ObjectUtil.isNull(voClassName)){
                            voClassName = adfTable.getTableName();
                        }
                        String sql = adfTable.getSql();
                        String packageName = "";
                        objectMap.put("voQuery_VoClassName",voClassName);
                        objectMap.put("AdfTableQuery",adfTable);
                        generateVO("4",voClassName, sql,packageName,customFiles,objectMap,x);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }


            }
            else if(templatePath.contains("vo.query.service.impl")){
                System.out.println("生成 vo.query.service.impl");

                try {

                    List<AdfTable> lstTable = GlobalConfig.globalQueryList.findAll(table->{return true;                    });

                    for(AdfTable adfTable : lstTable)
                    {
                        String voClassName = adfTable.getEntityName();
                        if(ObjectUtil.isNull(voClassName)){
                            voClassName = adfTable.getTableName();
                        }
                        String sql = adfTable.getSql();
                        String packageName = "";
                        objectMap.put("voQuery_VoClassName",voClassName);
                        objectMap.put("AdfTableQuery",adfTable);
                        generateVO("5",voClassName, sql,packageName,customFiles,objectMap,x);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });

    }

    private Map<String, String> parseOriginalMapperXml(String xmlPath) throws DocumentException {
        Map<String, String> result = new HashMap<>();
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(xmlPath));
        Element root = document.getRootElement();
        List<Element> selectElements = root.elements("select");
        for (Element select : selectElements) {
            result.put(select.attributeValue("id"), select.getTextTrim());
        }
        return result;
    }

    /**
     * 生成包含 mapper.xml 以及vo的实体
     * @param voClassName
     * @param sql
     * @param packageName
     * @param customFiles
     * @param objectMap
     * @param customFile
     */
    private void  generateVO(String type,String voClassName, String sql, String packageName,@NotNull List<CustomFile> customFiles,@NotNull Map<String, Object> objectMap,CustomFile customFile)
    {

        Setting setting = (Setting)objectMap.get("setting");
        String dbUrl = setting.get("db.url");
        String dbUsername = setting.get("db.username");
        String dbPassword = setting.get("db.password");
        String projectRootDir = setting.getStr("targetProject",System.getProperty("user.dir"));
        String MAPPER_XML_OUTPUT_DIR = projectRootDir +"/"+ TemplateUtil.createEngine().getTemplate(setting.get("mapperXmlOutPath")).render(setting);
        String voOutPath = projectRootDir +"/"+ TemplateUtil.createEngine().getTemplate(setting.get("voOutPath")).render(setting);
        String mapperOutPath =projectRootDir +"/"+ TemplateUtil.createEngine().getTemplate(setting.get("mapperOutPath")).render(setting);
        String queryInterfaceServiceOutPath =projectRootDir +"/"+ TemplateUtil.createEngine().getTemplate(setting.get("serviceOutPath")).render(setting);
        String queryImplServiceOutPath = queryInterfaceServiceOutPath + "/impl";
        List<AdfTableField> lstField = new ArrayList<>();
        DataSourceConfig.Builder builder = new DataSourceConfig.Builder(dbUrl,dbUsername,dbPassword);

        DataSourceConfig config = builder.build();
        Connection conn = config.getConn();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            System.out.println("当前Sql" + sql);
            pstmt = conn.prepareStatement(sql);
            // 4. 执行查询（返回结果集）
            rs = pstmt.executeQuery();
            // 3. 获取结果集元数据（包含字段信息）
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            System.out.println("查询结果共 " + columnCount + " 个字段：");
            for (int i = 1; i <= columnCount; i++) { // 注意：字段索引从 1 开始
                String columnName = metaData.getColumnName(i); // 字段名（数据库列名）
                System.out.println("列名" + columnName);
                String columnLabel = metaData.getColumnLabel(i); // 字段别名（如 AS 后的名称）
                String columnType = metaData.getColumnTypeName(i); // 数据库字段类型（如 INT、VARCHAR）
                int columnLength = metaData.getColumnDisplaySize(i); // 字段长度
                String javaType = metaData.getColumnClassName(i); // 对应的 Java 类型（全类名）



                AdfTableField tableField = new AdfTableField();
                tableField.setColumnName(columnName);
                tableField.setColumnLabel(columnLabel);
                tableField.setColumnTypeName(columnType);
                tableField.setColumnLength(columnLength);
                tableField.setJavaType(javaType);

                lstField.add(tableField);

            }

            if("1".equals(type)){
                // 生成vo
                String xmlFile = voOutPath + "/" +voClassName +"VO.java";
                System.out.println("xmlFile" + xmlFile);
                objectMap.put("fields",lstField);
                outputFile(new File(xmlFile),objectMap,customFile.getTemplatePath(),customFile.isFileOverride());
            }
            else if("2".equals(type)){
                // mapper.xml
                objectMap.put("fields",lstField);
                objectMap.put("sql",sql);
                String xmlFile = MAPPER_XML_OUTPUT_DIR + "//" +voClassName + "Mapper.xml";;
                outputFile(new File(xmlFile),objectMap,customFile.getTemplatePath(),customFile.isFileOverride());
            }
            else if("3".equals(type)){
                //mapper对应的java文件
                objectMap.put("fields",lstField);
                objectMap.put("sql",sql);
                String xmlFile = mapperOutPath + "//" +voClassName+"Mapper.java";
                outputFile(new File(xmlFile),objectMap,customFile.getTemplatePath(),customFile.isFileOverride());
            }
            else if("4".equals(type)){
                // query 服务的 interface
                AdfTable adfTable = (AdfTable)objectMap.get("AdfTableQuery");
                objectMap.put("fields",lstField);
                objectMap.put("sql",sql);

                String entityName = adfTable.getEntityName();
                if(ObjectUtil.isNull(entityName)){
                    entityName = adfTable.getTableName();
                }

                String saveFile = queryInterfaceServiceOutPath + "/I" +entityName+"Service.java";

                outputFile(new File(saveFile),objectMap,customFile.getTemplatePath(),customFile.isFileOverride());
            }
            else if("5".equals(type)){
                // query 服务的 interface
                AdfTable adfTable = (AdfTable)objectMap.get("AdfTableQuery");
                objectMap.put("fields",lstField);
                objectMap.put("sql",sql);

                String entityName = adfTable.getEntityName();
                if(ObjectUtil.isNull(entityName)){
                    entityName = adfTable.getTableName();
                }

                String saveFile = queryInterfaceServiceOutPath + "/impl/" +entityName+"ServiceImpl.java";

                String templatePath = customFile.getTemplatePath();
                outputFile(new File(saveFile),objectMap,templatePath,customFile.isFileOverride());
            }
        }catch (Exception e){
            System.out.println("xxx" + e.getMessage());



        }finally {
            // 6. 释放资源（按 ResultSet → PreparedStatement → Connection 顺序关闭）
            try {
                if (rs != null) rs.close();
                if (pstmt != null) pstmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                System.err.println("资源释放异常：" + e.getMessage());
            }
        }





        //outputFile(new File(""),objectMap,customFile.getTemplatePath(),customFile.isFileOverride());
    }


}
